/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package estructurassa.expertos;

import estructurassa.DTOs.DTOCostoVariable;
import estructurassa.DTOs.DTOPuntoEquilibrio;
import estructurassa.entidades.CentroMaquinaria;
import estructurassa.entidades.CostoFijo;
import estructurassa.entidades.DetalleOrden;
import estructurassa.entidades.DetalleProducto;
import estructurassa.entidades.EstadoOrdenDeProduccion;
import estructurassa.entidades.EtapaFabricacion;
import estructurassa.entidades.Material;
import estructurassa.entidades.OrdenDeProduccion;
import estructurassa.entidades.Precio;
import estructurassa.entidades.ProductoStandar;
import estructurassa.entidades.ProductoTerminado;
import estructurassa.entidades.Trabajador;
import estructurassa.expertos.excepciones.ProductoStandarException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.criterion.Restrictions;
import persistencia.Fachada;
import persistencia.exceptions.ExcepcionFachada;

/**
 *
 * @author Juan
 */
public class ExpertoCostosYProductoStandar implements Experto {

    public void nuevoProductoStandar(ProductoStandar productoStandarNuevo) throws ExcepcionFachada {

        try {
            validar(productoStandarNuevo);
        } catch (ProductoStandarException ex) {
            ex.printStackTrace();
        }

        Criteria criterio = Fachada.getInstancia().crearCriterio(ProductoStandar.class);

        List productosStandarEncontrados = Fachada.getInstancia().buscar(ProductoStandar.class, criterio);
        for (Object object : productosStandarEncontrados) {
            ProductoStandar encontrado = ((ProductoStandar) object);
            encontrado.setVigente(false);

            Fachada.getInstancia().guardar(encontrado);
        }


        Fachada.getInstancia().guardar(productoStandarNuevo);
        actualizarEquivalencias(productoStandarNuevo.getProductoStandar().getCosto());
    }

    public List buscarProductosStandar() {
        return Fachada.getInstancia().buscar(ProductoStandar.class, null);
    }

    public List buscarProductosStandarVigente() {
        Criteria criterio = Fachada.getInstancia().crearCriterio(ProductoStandar.class);
        criterio.add(Restrictions.eq("vigente", true));
        return Fachada.getInstancia().buscar(ProductoStandar.class, criterio);
    }

    public List buscarProductosStandar(Date fechaDesde, Date fechaHasta) {
        Criteria criterio = Fachada.getInstancia().crearCriterio(ProductoStandar.class);

        criterio.add(Restrictions.between("fechaDesde", fechaDesde, fechaHasta));
        criterio.add(Restrictions.between("fechaHasta", fechaDesde, fechaHasta));

        return Fachada.getInstancia().buscar(ProductoStandar.class, criterio);
    }

    private void validar(ProductoStandar producto) throws ProductoStandarException {
//        if (producto.getFechaDesde() == null) {
//            throw new ProductoStandarException("No se ha ingresado fecha desde");
//        }
//        if (producto.getFechaHasta() == null) {
//            throw new ProductoStandarException("No se ha ingresado fecha hasta");
//        }
//        if (producto.getProductoStandar() == null) {
//            throw new ProductoStandarException("No se ha seleccionado producto");
//        }
    }

    public void darDeBaja(ProductoStandar producto) throws ExcepcionFachada {
        producto.setVigente(false);
        Fachada.getInstancia().guardar(producto);
    }

    public void calcularEquivalencias() throws ExcepcionFachada {
        ProductoStandar productoVigente = buscarProductoStandarVigente();

        Float costoProductoStandarVigente = calcularCostoProducto(productoVigente.getProductoStandar());

        actualizarEquivalencias(costoProductoStandarVigente);
    }

    private Float calcularCostoProducto(ProductoTerminado productoTerminado) {
        List detallesProducto = productoTerminado.getDetalles();
        Float costoProducto = 0f;

        for (Object object : detallesProducto) {
            Float costoMaterial;
            DetalleProducto detalle = (DetalleProducto) object;
            Float cantidad = detalle.getCantidad();

            Float precioUnitario = 0f;
            if (detalle.getPieza() instanceof Material) {
                precioUnitario = calcularCostoXUnidad((Material) detalle.getPieza());
            } else if (detalle.getPieza() instanceof ProductoTerminado) {
                precioUnitario = ((ProductoTerminado) detalle.getPieza()).getCosto();
            }
            costoMaterial = cantidad * precioUnitario;
            costoProducto += costoMaterial;
        }
        return costoProducto;
    }

    private Float calcularCostoXUnidad(Material material) {

        Float menorPrecio = material.getPrecios().get(0).getMonto();
        for (Precio precio : material.getPrecios()) {
            if (precio.getMonto() < menorPrecio) {
                menorPrecio = precio.getMonto();
            }
        }
        Float costoUnitario = menorPrecio / material.getTamaño();
        return costoUnitario;
    }

    private ProductoStandar buscarProductoStandarVigente() {
        Criteria productoStandarVigente = Fachada.getInstancia().crearCriterio(ProductoStandar.class);
        productoStandarVigente.add(Restrictions.eq("vigente", true));
        List productosencontrados = Fachada.getInstancia().buscar(ProductoStandar.class, productoStandarVigente);
        ProductoStandar productoVigente = new ProductoStandar();
        for (Object object : productosencontrados) {
            productoVigente = ((ProductoStandar) object);
        }
        return productoVigente;
    }

    private void actualizarEquivalencias(Float costoProductoStandar) throws ExcepcionFachada {
        List productos = Fachada.getInstancia().buscar(ProductoTerminado.class, null);
        for (Object prod : productos) {
            ProductoTerminado producto = ((ProductoTerminado) prod);
            Float equivalencia = calcularCostoProducto(((ProductoTerminado) prod)) / costoProductoStandar;
            producto.setEquivalenciaRespectoProductoStandar(equivalencia);
            Fachada.getInstancia().guardar(producto);
        }
    }

    public Float calcularCostoFijo(Date fechaDesde, Date fechaHasta) {

        Float costoFijo = 0f;

        Criteria criteriofechas = Fachada.getInstancia().crearCriterio(CostoFijo.class);
        if (fechaHasta == null) {
            fechaHasta = new Date();
        }
        criteriofechas.add(Restrictions.between("fechaDesde", fechaDesde, fechaHasta));
        criteriofechas.add(Restrictions.between("fechaHasta", fechaDesde, fechaHasta));

        List costosfijosperiodo = Fachada.getInstancia().buscar(CostoFijo.class, criteriofechas);

        for (Object object : costosfijosperiodo) {
            costoFijo = costoFijo + ((CostoFijo) object).getMonto();
        }


        return costoFijo;
    }

    public Float calcularCostoVariableTotal(ProductoTerminado producto) {
        Float costoVariable = 0f;

        costoVariable = producto.getCosto() + calcularCostoHorasHombres(producto) + calcularCostoHorasMaquina(producto);

        return costoVariable;
    }

    public List<DTOCostoVariable> calcularCostoVariable() {
        Criteria criterio = Fachada.getInstancia().crearCriterio(ProductoTerminado.class);
        List listaProductos = Fachada.getInstancia().buscar(ProductoTerminado.class, criterio);

        List<DTOCostoVariable> listaDTO = new ArrayList<>();

        for (Object object : listaProductos) {
            ProductoTerminado prod = ((ProductoTerminado) object);

            DTOCostoVariable dto = new DTOCostoVariable();
            dto.setProducto(prod);
            dto.setCostoManoDeObra(calcularCostoHorasHombres(prod));
            dto.setCostoHorasMaquina(calcularCostoHorasMaquina(prod));
            listaDTO.add(dto);

        }

        return listaDTO;
    }

    public Float calcularCostoHorasHombres(ProductoTerminado producto) {
        Float horasTrabajadas = 0f;


        List<EtapaFabricacion> etapasProducto = producto.getRutaFabricacion().getEstapasFabricacion();
        for (EtapaFabricacion etapaFabricacion : etapasProducto) {


            List<Trabajador> listaTrabajadores = etapaFabricacion.getCentroDeTrabajo().getListadoTrabajadores();
            for (Trabajador trabajador : listaTrabajadores) {
                horasTrabajadas = etapaFabricacion.getDuracion() * (trabajador.getCategoria().getRemuneracion()/176);
            }

        }



        return horasTrabajadas;
    }

    public Float calcularCostoHorasMaquina(ProductoTerminado producto) {

        Float horasMaquina = 0f;

        List<EtapaFabricacion> etapasProducto = producto.getRutaFabricacion().getEstapasFabricacion();
        for (EtapaFabricacion etapaFabricacion : etapasProducto) {
            horasMaquina += etapaFabricacion.getMaquina().getPrecioConsumoHora()*etapaFabricacion.getDuracion();
//            List<CentroMaquinaria> centrosMaquinaria = etapaFabricacion.getCentroDeTrabajo().getListadoCentroMaquinarias();
//            for (CentroMaquinaria centroMaquinaria : centrosMaquinaria) {
//                horasMaquina = centroMaquinaria.getMaquina().getPrecioConsumoHora() * etapaFabricacion.getDuracion() * centroMaquinaria.getCantidad();
//            }
        }



        return horasMaquina;
    }

    public List<CostoFijo> buscarCostosDeMesYAnio(String mes, String anio) {
        List<CostoFijo> costo = new ArrayList<>();
        Criteria criterioCosto = Fachada.getInstancia().crearCriterio(CostoFijo.class);
        criterioCosto.add(Restrictions.eq("mes", mes));
        criterioCosto.add(Restrictions.eq("anio", anio));
        List listaCostosFijos = Fachada.getInstancia().buscar(CostoFijo.class, criterioCosto);
        for (Object object : listaCostosFijos) {

            costo.add((CostoFijo) object);

        }

        return costo;
    }

    public DTOPuntoEquilibrio calcularPtoEquilibrioEstandar(String mes, String anio) {
        ProductoStandar prodvigente = buscarProductoStandarVigente();
        List<CostoFijo> lista = buscarCostosDeMesYAnio(mes, anio);
        Float costoFijoTot = calcularCostoFijoPeriodoTotal(lista);
        Float costoVarTotal = calcularCostoVariableTotal(prodvigente.getProductoStandar());
        Float precioDeVenta = prodvigente.getProductoStandar().getPrecio();

        Float cantidadEquilibrio = costoFijoTot / (precioDeVenta - costoVarTotal);
        Float precioEquilibrio = cantidadEquilibrio * prodvigente.getProductoStandar().getPrecio();

        DTOPuntoEquilibrio dto = new DTOPuntoEquilibrio();

        dto.setCantidadEquilibrio(cantidadEquilibrio);
        dto.setCostoFijoTot(costoFijoTot);
        dto.setCostoVarTotal(costoVarTotal);
        dto.setPrecioDeVenta(precioDeVenta);
        dto.setPrecioEquilibrio(precioEquilibrio);
        dto.setProdvigente(prodvigente);

        return dto;

    }

    public DTOPuntoEquilibrio calcularPtoEquilibrio(String mes, String anio) {

        ProductoStandar prodvigente = buscarProductoStandarVigente();
        List<CostoFijo> listaCostosFijos = buscarCostosDeMesYAnio(mes, anio);
        Float costoFijoTot = calcularCostoFijoPeriodoTotal(listaCostosFijos);
        Float costoVarTotal = calcularCostoVariableTotal(prodvigente.getProductoStandar());
        Float precioDeVenta = prodvigente.getProductoStandar().getPrecio();

        Float cantidadEquilibrio = costoFijoTot / (precioDeVenta - costoVarTotal);
        Float precioEquilibrio = cantidadEquilibrio * prodvigente.getProductoStandar().getPrecio();
        Float costoVariableConEquivalencias = 0f;
        
        
        

        Criteria criterioEstado = Fachada.getInstancia().crearCriterio(EstadoOrdenDeProduccion.class);
        criterioEstado.add(Restrictions.like("estado", "Entregada").ignoreCase());
        EstadoOrdenDeProduccion estado = (EstadoOrdenDeProduccion) Fachada.getInstancia().buscar(OrdenDeProduccion.class, criterioEstado).get(0);

        Criteria criterioOrden = Fachada.getInstancia().crearCriterio(OrdenDeProduccion.class);
        criterioOrden.createCriteria("estados").add(Restrictions.eq("estado", estado));
        List ordenes = Fachada.getInstancia().buscar(OrdenDeProduccion.class, criterioOrden);

        for (Object ordenSinCastear : ordenes) {
            OrdenDeProduccion ordenDeProd = ((OrdenDeProduccion) ordenSinCastear);
            if (ordenDeProd.getFechaDeOrden().getMonth() == Integer.valueOf(mes) && ordenDeProd.getFechaDeOrden().getYear() + 1900 == Integer.valueOf(anio)) {
            
                
                List listaDetallesOrden = ordenDeProd.getListaDetalles();
                for (Object det : listaDetallesOrden) {
                    costoVariableConEquivalencias = costoVariableConEquivalencias + (((DetalleOrden)det).getProductoTerminado().getEquivalenciaRespectoProductoStandar() * prodvigente.getProductoStandar().getPrecio() * ((DetalleOrden)det).getCantidad());
                }
                
            }

        }



        DTOPuntoEquilibrio dto = new DTOPuntoEquilibrio();

        dto.setCantidadEquilibrio(cantidadEquilibrio);
        dto.setCostoFijoTot(costoFijoTot);
        dto.setCostoVarTotal(costoVariableConEquivalencias);
        dto.setPrecioDeVenta(precioDeVenta);
        dto.setPrecioEquilibrio(precioEquilibrio);
        dto.setProdvigente(prodvigente);

        return dto;

    }

    private Float calcularCostoFijoPeriodoTotal(List<CostoFijo> lista) {
        Float total = 0f;
        for (CostoFijo costoFijo : lista) {
            total = costoFijo.getMonto() + total;
        }

        return total;
    }
}
